package org.freez4.spring.dependency.lookup;

import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 依赖查找常见的异常演示demo。
 *
 * @author 阿坤同学
 * @date 2023/12/8 3:39 PM
 */
public class LookupExceptionDemo {

    private static final Logger logger = Logger.getLogger(LookupExceptionDemo.class.getName());

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        beanCreationExceptionDemo();
        beanInstantiationExceptionDemo();
        noUniqueBeanDefinitionExceptionDemo();

        // 关闭应用上下文
        applicationContext.close();
    }

    /**
     * 演示bean 初始化时发生的异常。
     *
     * @author 阿坤同学
     * @date 2023/12/8 3:55 PM
     */
    private static void beanCreationExceptionDemo() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 BeanDefinition Bean Class 是一个 POJO 普通类，不过初始化方法回调时抛出异常
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(POJO.class);
        applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());
        try {
            applicationContext.refresh();
        } catch (BeanCreationException bce) {
            logger.log(Level.INFO, String.format("Bean 初始化异常:%s", bce.getMessage()));
        }
    }

    /**
     * 当接口注入IoC中发生的异常。
     *
     * @author 阿坤同学
     * @date 2023/12/8 4:10 PM
     */
    private static void beanInstantiationExceptionDemo() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 注册 BeanDefinition Bean Class 是一个 CharSequence 接口
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(CharSequence.class);
        applicationContext.registerBeanDefinition("errorBean", beanDefinitionBuilder.getBeanDefinition());
        try {
            applicationContext.refresh();
        } catch (BeanInstantiationException bie) {
            logger.log(Level.INFO, String.format("注册BeanDefinition并非是个接口并非实现类:%s", bie.getMessage()));
        }
    }

    /**
     * 当IoC存在多个相同类型的Bean时，通过单一查找发生的异常。
     *
     * @author 阿坤同学
     * @date 2023/12/8 4:14 PM
     */
    private static void noUniqueBeanDefinitionExceptionDemo() {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        try {
            // 由于 Spring 应用上下文存在两个 String 类型的 Bean，通过单一类型查找会抛出异常
            applicationContext.refresh();
            applicationContext.getBean(String.class);
        } catch (NoUniqueBeanDefinitionException e) {
            logger.log(Level.INFO, String.format("Spring 应用上下文存在%d个 %s 类型的 Bean，具体原因：%s%n", e.getNumberOfBeansFound(), String.class.getName(), e.getMessage()));
        }
    }


    static class POJO implements InitializingBean {

        private Integer x;

        @PostConstruct
        public void init() {
            if (x == null) {
                throw new IllegalArgumentException("x value is null,initialization failure");
            }
        }

        @Override
        public void afterPropertiesSet() {
            if (x == null) {
                throw new IllegalArgumentException("x value is null,initialization failure");
            }
        }
    }

    @Bean
    public String bean1() {
        return "1";
    }

    @Bean
    public String bean2() {
        return "2";
    }

    @Bean
    public String bean3() {
        return "3";
    }

}
